{ "cells": [ { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "# Conditional Execution" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "-" }, "tags": [ "remove-cell" ] }, "source": [ "**CS1302 Introduction to Computer Programming**\n", "___" ] }, { "cell_type": "code", "execution_count": 14, "metadata": { "ExecuteTime": { "end_time": "2020-11-27T11:20:04.656873Z", "start_time": "2020-11-27T11:20:04.651575Z" }, "slideshow": { "slide_type": "fragment" }, "tags": [ "remove-cell" ] }, "outputs": [], "source": [ "import math\n", "\n", "%reload_ext mytutor" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "## Motivation" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "Conditional execution means running different pieces of code based on different conditions. Why?" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "For instance, when trying to compute `a/b`, `b` may be `0` and division by `0` is invalid." ] }, { "cell_type": "code", "execution_count": 22, "metadata": { "ExecuteTime": { "end_time": "2020-09-12T03:08:48.958533Z", "start_time": "2020-09-12T03:08:48.942735Z" }, "scrolled": true, "slideshow": { "slide_type": "-" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "a:1, b:2, a*b:2, a/b:0.5\n" ] }, { "ename": "ZeroDivisionError", "evalue": "division by zero", "output_type": "error", "traceback": [ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", "\u001b[0;31mZeroDivisionError\u001b[0m Traceback (most recent call last)", "\u001b[0;32m/tmp/ipykernel_2917/1699305966.py\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[1;32m 4\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 5\u001b[0m \u001b[0mmultiply_or_divide\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;36m1\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;36m2\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 6\u001b[0;31m \u001b[0mmultiply_or_divide\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;36m1\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;36m0\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;31m# multiplication is valid but not shown\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", "\u001b[0;32m/tmp/ipykernel_2917/1699305966.py\u001b[0m in \u001b[0;36mmultiply_or_divide\u001b[0;34m(a, b)\u001b[0m\n\u001b[1;32m 1\u001b[0m \u001b[0;32mdef\u001b[0m \u001b[0mmultiply_or_divide\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0ma\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mb\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 2\u001b[0;31m \u001b[0mprint\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m\"a:{}, b:{}, a*b:{}, a/b:{}\"\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mformat\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0ma\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mb\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0ma\u001b[0m \u001b[0;34m*\u001b[0m \u001b[0mb\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0ma\u001b[0m \u001b[0;34m/\u001b[0m \u001b[0mb\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 3\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 4\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 5\u001b[0m \u001b[0mmultiply_or_divide\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;36m1\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;36m2\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", "\u001b[0;31mZeroDivisionError\u001b[0m: division by zero" ] } ], "source": [ "def multiply_or_divide(a, b):\n", " print(\"a:{}, b:{}, a*b:{}, a/b:{}\".format(a, b, a * b, a / b))\n", "\n", "\n", "multiply_or_divide(1, 2)\n", "multiply_or_divide(1, 0) # multiplication is valid but not shown" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "Can we skip only the division but not multiplication when `b` is `0`?" ] }, { "cell_type": "code", "execution_count": 2, "metadata": { "ExecuteTime": { "end_time": "2020-09-11T23:45:09.013086Z", "start_time": "2020-09-11T23:45:09.006583Z" }, "slideshow": { "slide_type": "fragment" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "a:1, b:2, a*b:2, a/b:0.5\n", "a:1, b:0, a*b:0, a/b:undefined\n" ] } ], "source": [ "def multiply_or_divide(a, b):\n", " fix = a / b if b else \"undefined\"\n", " print(\"a:{}, b:{}, a*b:{}, a/b:{}\".format(a, b, a * b, fix))\n", "\n", "\n", "multiply_or_divide(1, 2)\n", "multiply_or_divide(1, 0) # multiplication is valid but not shown" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "The above solution involves:\n", "\n", "- a *boolean expression* `fix` that checks whether a condition holds, and\n", "- a *conditional construct* `... if ... else ...` that specify which code block should be executed under what condition." ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "## Boolean expressions" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "### Comparison Operators" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "**How to compare different values?**" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "Like the equality and inequality relationships in mathematics, Python also has binary [*comparison/relational operators*](https://docs.python.org/3/reference/expressions.html#comparisons):" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "-" } }, "source": [ "| Expression | True iff |\n", "| ---------: | :--------- |\n", "| `x == y` | $x=y$. |\n", "| `x < y` | $x y` | $x>y$. |\n", "| `x >= y` | $x\\geq y$. |\n", "| `x != y` | $x\\neq y$. |" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "Explore these operators using the widgets below:" ] }, { "cell_type": "code", "execution_count": 3, "metadata": { "ExecuteTime": { "end_time": "2020-09-11T23:49:58.452860Z", "start_time": "2020-09-11T23:49:58.406808Z" }, "code_folding": [ 0 ], "scrolled": true, "slideshow": { "slide_type": "-" } }, "outputs": [ { "data": { "application/vnd.jupyter.widget-view+json": { "model_id": "107557cda3754149a7e51cae849a694f", "version_major": 2, "version_minor": 0 }, "text/plain": [ "interactive(children=(Text(value='10', description='operand1'), Dropdown(description='operator', options=('=='…" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "# Comparisons\n", "from ipywidgets import interact\n", "\n", "comparison_operators = [\"==\", \"<\", \"<=\", \">\", \">=\", \"!=\"]\n", "\n", "\n", "@interact(operand1=\"10\", operator=comparison_operators, operand2=\"3\")\n", "def comparison(operand1, operator, operand2):\n", " expression = f\"{operand1} {operator} {operand2}\"\n", " value = eval(expression)\n", " print(\n", " f\"\"\"{'Expression:':>11} {expression}\\n{'Value:':>11} {value}\\n{'Type:':>11} {type(value)}\"\"\"\n", " )" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "- These operators return either `True` or `False`, which are `keywords` of type *boolean*.\n", "- The expressions are called *boolean expressions* or *predicates*, named after [George Boole](https://en.wikipedia.org/wiki/George_Boole).\n", "- N.b., the equality operator `==` consists of *two equal signs*, different from the assignment operator `=`." ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "**What is the precedence of comparison operators?**" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ " All the comparison operators have the [same precedence](https://docs.python.org/3/reference/expressions.html?highlight=precedence#operator-precedence) lower than that of `+` and `-`." ] }, { "cell_type": "code", "execution_count": 4, "metadata": { "ExecuteTime": { "end_time": "2020-09-11T23:52:19.106039Z", "start_time": "2020-09-11T23:52:19.092278Z" }, "slideshow": { "slide_type": "fragment" } }, "outputs": [ { "data": { "text/plain": [ "True" ] }, "execution_count": 4, "metadata": {}, "output_type": "execute_result" } ], "source": [ "1 + 2 >= 3 # (1 + 2) >= 3" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "Python allows multiple comparison operations to be chained together:" ] }, { "cell_type": "code", "execution_count": 5, "metadata": { "ExecuteTime": { "end_time": "2020-09-12T05:54:39.873338Z", "start_time": "2020-09-12T05:54:39.867318Z" }, "slideshow": { "slide_type": "-" } }, "outputs": [ { "data": { "text/plain": [ "True" ] }, "execution_count": 5, "metadata": {}, "output_type": "execute_result" } ], "source": [ "2.0 == 2 > 1 # equivalent to (2.0 ==2) and (2>1)" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "**What is the associativity?**" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "Comparison operations are [*non-associative*](https://en.wikipedia.org/wiki/Operator_associativity#Non-associative_operators):" ] }, { "cell_type": "code", "execution_count": 6, "metadata": { "ExecuteTime": { "end_time": "2020-09-11T23:53:21.557499Z", "start_time": "2020-09-11T23:53:21.548954Z" }, "slideshow": { "slide_type": "-" } }, "outputs": [ { "data": { "text/plain": [ "(False, False)" ] }, "execution_count": 6, "metadata": {}, "output_type": "execute_result" } ], "source": [ "(2.0 == 2) > 1, 2.0 == (2 > 1) # not the same as 2.0 == 2 > 1" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "**Exercise** Explain why the following boolean expressions have different values." ] }, { "cell_type": "code", "execution_count": 10, "metadata": { "ExecuteTime": { "end_time": "2020-09-11T23:56:55.242691Z", "start_time": "2020-09-11T23:56:55.234247Z" }, "slideshow": { "slide_type": "-" } }, "outputs": [ { "data": { "text/plain": [ "(True, False)" ] }, "execution_count": 10, "metadata": {}, "output_type": "execute_result" } ], "source": [ "1 <= 2 < 3 != 4, (1 <= 2) < (3 != 4)" ] }, { "cell_type": "markdown", "metadata": { "ExecuteTime": { "end_time": "2020-09-08T04:47:41.928758Z", "start_time": "2020-09-08T04:47:41.922830Z" }, "nbgrader": { "grade": true, "grade_id": "chained_relational_operator", "locked": false, "points": 0, "schema_version": 3, "solution": true, "task": false }, "slideshow": { "slide_type": "-" } }, "source": [ "The second expression is not a chained comparison: \n", "- The expressions in the parentheses are evaluated to boolean values first to `True`, and so\n", "- the overall expression `True < True` is evaluated to `False`." ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "**Exercise** The comparison operators can be applied to different data types, as illustrated below. \n", "Explain the meaning of the operators in each of the following expressions." ] }, { "cell_type": "code", "execution_count": 7, "metadata": { "ExecuteTime": { "end_time": "2020-09-11T23:58:13.970230Z", "start_time": "2020-09-11T23:58:13.939398Z" }, "code_folding": [ 0 ], "scrolled": true, "slideshow": { "slide_type": "-" } }, "outputs": [ { "data": { "application/vnd.jupyter.widget-view+json": { "model_id": "e314356227674c3394e99ace3ec39ce7", "version_major": 2, "version_minor": 0 }, "text/plain": [ "interactive(children=(Dropdown(description='expression', options=('10 == 10.', '\"A\" == \"A\"', '\"A\" == \"A \"', '\"…" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "# Comparisons beyond numbers\n", "@interact(\n", " expression=[\n", " \"10 == 10.\",\n", " '\"A\" == \"A\"',\n", " '\"A\" == \"A \"',\n", " '\"A\" != \"a\"',\n", " '\"A\" > \"a\"',\n", " '\"aBcd\" < \"abd\"',\n", " '\"A\" != 64',\n", " '\"A\" < 64',\n", " ]\n", ")\n", "def relational_expression(expression):\n", " print(eval(expression))" ] }, { "cell_type": "markdown", "metadata": { "ExecuteTime": { "end_time": "2020-09-07T12:00:24.402195Z", "start_time": "2020-09-07T12:00:24.395752Z" }, "nbgrader": { "grade": true, "grade_id": "relational_expression", "locked": false, "points": 0, "schema_version": 3, "solution": true, "task": false }, "slideshow": { "slide_type": "-" } }, "source": [ "1. Checks whether an integer is equal to a floating point number.\n", "1. Checks whether two characters are the same.\n", "1. Checks whether two strings are the same. Note the space character.\n", "1. Checks whether a character is larger than the order character according to their unicodes.\n", "1. Checks whether a string is lexicographically smaller than the other string.\n", "1. Checks whether a character is not equal to an integer.\n", "1. TypeError because there is no implementation that evaluates whether a string is smaller than an integer." ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "**Is `!` the same as the `not` operator?**" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "Different from C language: \n", "\n", "- We can write `1 != 2` as `not 1 == 2` but not `!(1 == 2)` because\n", "- `!` is not a logical operator. It is used to call a [system shell command](https://ipython.readthedocs.io/en/stable/interactive/tutorial.html?highlight=system%20call#system-shell-commands) in IPython." ] }, { "cell_type": "code", "execution_count": 8, "metadata": { "ExecuteTime": { "end_time": "2020-09-08T15:02:31.529274Z", "start_time": "2020-09-08T15:02:31.405018Z" }, "slideshow": { "slide_type": "fragment" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "/bin/bash: 1: command not found\n" ] } ], "source": [ "!(1 == 2)" ] }, { "cell_type": "code", "execution_count": 9, "metadata": { "ExecuteTime": { "end_time": "2020-09-08T15:03:43.371177Z", "start_time": "2020-09-08T15:03:43.251153Z" }, "slideshow": { "slide_type": "-" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "'Conditional Execution.ipynb' 'Conditional Execution.md' Iteration.ipynb\n" ] } ], "source": [ "!ls # a bash command that lists files in the current directory" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "**How to compare floating point numbers?**" ] }, { "cell_type": "code", "execution_count": 10, "metadata": { "ExecuteTime": { "end_time": "2020-09-12T00:37:27.688549Z", "start_time": "2020-09-12T00:37:27.681227Z" }, "slideshow": { "slide_type": "fragment" } }, "outputs": [ { "data": { "text/plain": [ "False" ] }, "execution_count": 10, "metadata": {}, "output_type": "execute_result" } ], "source": [ "x = 10\n", "y = (x ** (1 / 3)) ** 3\n", "x == y" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "Why False? Shouldn't $(x^{\\frac13})^3=x$?" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "- Floating point numbers have finite precisions and so \n", "- we should instead check whether the numbers are close enough." ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "One method of comparing floating point numbers:" ] }, { "cell_type": "code", "execution_count": 11, "metadata": { "ExecuteTime": { "end_time": "2020-09-12T00:38:17.357180Z", "start_time": "2020-09-12T00:38:17.349848Z" }, "slideshow": { "slide_type": "fragment" } }, "outputs": [ { "data": { "text/plain": [ "True" ] }, "execution_count": 11, "metadata": {}, "output_type": "execute_result" } ], "source": [ "abs(x - y) <= 1e-9" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "`abs` is a function that returns the absolute value of its argument. Hence, the above translates to\n", "\n", "$$|x - y| \\leq \\delta_{\\text{abs}}$$ \n", "or equivalently \n", "\n", "$$y-\\delta_{\\text{abs}} \\leq x \\leq y+\\delta_{\\text{abs}} $$\n", "where $\\delta_{\\text{abs}}$ is called the *absolute tolerance*." ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "**Is an absolute tolerance of `1e-9` good enough?**" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "What if we want to compare `x = 1e10` instead of `10`?" ] }, { "cell_type": "code", "execution_count": 12, "metadata": { "ExecuteTime": { "end_time": "2020-09-12T00:41:15.078354Z", "start_time": "2020-09-12T00:41:15.071548Z" }, "slideshow": { "slide_type": "fragment" } }, "outputs": [ { "data": { "text/plain": [ "False" ] }, "execution_count": 12, "metadata": {}, "output_type": "execute_result" } ], "source": [ "x = 1e10\n", "y = (x ** (1 / 3)) ** 3\n", "abs(x - y) <= 1e-9" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "Floating point numbers \"float\" at different scales. \n", "A better way is to use the [`isclose`](https://docs.python.org/3/library/math.html#math.isclose) function from `math` module." ] }, { "cell_type": "code", "execution_count": 15, "metadata": { "ExecuteTime": { "end_time": "2020-09-12T00:42:37.976759Z", "start_time": "2020-09-12T00:42:37.969252Z" }, "slideshow": { "slide_type": "fragment" } }, "outputs": [ { "data": { "text/plain": [ "True" ] }, "execution_count": 15, "metadata": {}, "output_type": "execute_result" } ], "source": [ "math.isclose(x, y)" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "**How does it work?**" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "`math.isclose(x,y)` implements\n", "\n", "$$ |x - y| \\leq \\max\\{\\delta_{\\text{rel}} \\max\\{|x|,|y|\\},\\delta_{\\text{abs}}\\}$$\n", "with the default\n", "- *relative tolerance* $\\delta_{\\text{rel}}$ equal to `1e-9`, and\n", "- absolute tolerance $\\delta_{\\text{abs}}$ equal to `0.0`." ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "**Exercise** Write the boolean expression implemented by `isclose`. You can use the function `max(a,b)` to find the maximum of `a` and `b`." ] }, { "cell_type": "code", "execution_count": 16, "metadata": { "ExecuteTime": { "end_time": "2020-09-12T00:32:30.526651Z", "start_time": "2020-09-12T00:32:30.516825Z" }, "nbgrader": { "grade": false, "grade_id": "isclose", "locked": false, "schema_version": 3, "solution": true, "task": false }, "slideshow": { "slide_type": "-" } }, "outputs": [ { "data": { "text/plain": [ "False" ] }, "execution_count": 16, "metadata": {}, "output_type": "execute_result" } ], "source": [ "rel_tol, abs_tol = 1e-9, 0.0\n", "x, y = 1e-100, 2e-100\n", "### BEGIN SOLUTION\n", "abs(x - y) <= max(rel_tol * max(abs(x), abs(y)), abs_tol)\n", "### END SOLUTION" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "### Boolean Operations" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "Since chained comparisons are non-associative, it follows a different evaluation rule than arithmetical operators." ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "E.g., `1 <= 2 < 3 != 4` is evaluated as follows:" ] }, { "cell_type": "code", "execution_count": 17, "metadata": { "ExecuteTime": { "end_time": "2020-09-12T00:49:20.552008Z", "start_time": "2020-09-12T00:49:20.544386Z" }, "slideshow": { "slide_type": "-" } }, "outputs": [ { "data": { "text/plain": [ "True" ] }, "execution_count": 17, "metadata": {}, "output_type": "execute_result" } ], "source": [ "1 <= 2 and 2 < 3 and 3 != 4" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "The above is called a *compound boolean expression*, which is formed using the *boolean/logical operator* `and`." ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "**Why use boolean operators?**" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "What if we want to check whether a number is either $< 0$ or $\\geq 100$? \n", "Can we achieve this only by chaining the comparison operators or applying the logical `and`?" ] }, { "cell_type": "code", "execution_count": 18, "metadata": { "ExecuteTime": { "end_time": "2020-09-12T02:04:11.344375Z", "start_time": "2020-09-12T02:04:11.303591Z" }, "code_folding": [], "slideshow": { "slide_type": "-" } }, "outputs": [ { "data": { "application/vnd.jupyter.widget-view+json": { "model_id": "a696ee9307e44fd0be9171c304bd2452", "version_major": 2, "version_minor": 0 }, "text/plain": [ "interactive(children=(Text(value='15', description='x'), Output()), _dom_classes=('widget-interact',))" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "# Check if a number is outside a range.\n", "@interact(x=\"15\")\n", "def check_out_of_range(x):\n", " x_ = float(x)\n", " is_out_of_range = x_ < 0 or x_ >= 100\n", " print(\"Out of range [0,100):\", is_out_of_range)" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "- `and` alone is not [functionally complete](https://en.wikipedia.org/wiki/Functional_completeness), i.e., not enough to give all possible boolean functions. \n", "- In addition to `and`, we can also use `or` and `not`." ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "| `x` | `y` | `x and y` | `x or y` | `not x` |\n", "| :-----: | :-----: | :-------: | :------: | :-----: |\n", "| `True` | `True` | `True` | `True` | `False` |\n", "| `True` | `False` | `False` | `True` | `False` |\n", "| `False` | `True` | `False` | `True` | `True` |\n", "| `False` | `False` | `False` | `False` | `True` |" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "The above table is called a *truth table*. It enumerates all possible input and output combinations for each boolean operator." ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "**How are chained logical operators evaluated? \n", "What are the precedence and associativity for the logical operators?**" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "- All binary boolean operators are left associative. \n", "- [Precedence](https://docs.python.org/3/reference/expressions.html?highlight=precedence#operator-precedence): `comparison operators` > `not` > `and` > `or`" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "**Exercise** Explain what the values of the following two compound boolean expressions are:\n", "- Expression A: `True or False and True`\n", "- Expression B: `True and False and True`\n", "- Expression C: `True or True and False`" ] }, { "cell_type": "markdown", "metadata": { "nbgrader": { "grade": true, "grade_id": "compound-boolean", "locked": false, "points": 0, "schema_version": 3, "solution": true, "task": false }, "slideshow": { "slide_type": "-" } }, "source": [ "- Expression A evaluates to `True` because `and` has higher precedence and so the expression has the same value as `True or (False and True)`.\n", "- Expression B evaluates to `False` because `and` is left associative and so the expression has the same value as `(True and False) and True`.\n", "- Expression C evaluates to `True` because `and` has a higher precedence and so the expression has the same value as `True or (True and False)`. Note that `(True or True) and False` evaluates to something `False` instead, so precedence matters." ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "Instead of following the precedence and associativity, however, a compound boolean expression uses a [short-circuit evaluation](https://docs.python.org/3/reference/expressions.html?highlight=precedence#boolean-operations)." ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "To understand this, we will use the following function to evaluate a boolean expression verbosely. \n", "(You may also use [Thonny](https://thonny.org/) for step-by-step evaluations of the following examples.)" ] }, { "cell_type": "code", "execution_count": 19, "metadata": { "ExecuteTime": { "end_time": "2020-09-12T01:05:45.113256Z", "start_time": "2020-09-12T01:05:45.107078Z" }, "slideshow": { "slide_type": "-" } }, "outputs": [], "source": [ "def verbose(id, boolean):\n", " \"\"\"Identify evaluated boolean expressions.\"\"\"\n", " print(id, \"evaluated:\", boolean)\n", " return boolean" ] }, { "cell_type": "code", "execution_count": 20, "metadata": { "ExecuteTime": { "end_time": "2020-09-12T01:04:35.273840Z", "start_time": "2020-09-12T01:04:35.262936Z" }, "slideshow": { "slide_type": "-" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "1 evaluated: True\n", "A evaluated: True\n" ] }, { "data": { "text/plain": [ "True" ] }, "execution_count": 20, "metadata": {}, "output_type": "execute_result" } ], "source": [ "verbose(\n", " \"A\", verbose(1, True) or verbose(2, False) and verbose(3, True)\n", ") # True or (False and True)" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "**Why expression 2 and 3 are not evaluated?**" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "Because True or ... must be True (why?) so Python does not look further. From the [documentation](https://docs.python.org/3/reference/expressions.html?highlight=precedence#boolean-operations):" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "> The expression `x or y` first evaluates `x`; \n", "> if `x` is true, its value is returned; \n", "> otherwise, `y` is evaluated and the resulting value is returned." ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "Note that:\n", "- Even though `or` has lower precedence than `and`, it is still evaluated first. \n", "- The evaluation order for logical operators is left-to-right." ] }, { "cell_type": "code", "execution_count": 48, "metadata": { "ExecuteTime": { "end_time": "2020-09-12T01:11:36.615347Z", "start_time": "2020-09-12T01:11:36.604893Z" }, "slideshow": { "slide_type": "subslide" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "4 evaluated: True\n", "5 evaluated: False\n", "B evaluated: False\n" ] }, { "data": { "text/plain": [ "False" ] }, "execution_count": 48, "metadata": {}, "output_type": "execute_result" } ], "source": [ "verbose(\n", " \"B\", verbose(4, True) and verbose(5, False) and verbose(6, True)\n", ") # (True and False) and True" ] }, { "cell_type": "markdown", "metadata": { "ExecuteTime": { "end_time": "2020-09-08T15:48:22.353601Z", "start_time": "2020-09-08T15:48:22.347753Z" }, "slideshow": { "slide_type": "subslide" } }, "source": [ "**Why expression 6 is not evaluated?**" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "`True and False and ...` must be `False` so Python does not look further." ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "> The expression `x and y` first evaluates `x`; \n", "> if `x` is false, its value is returned; \n", "> otherwise, `y` is evaluated and the resulting value is returned." ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "Indeed, logical operators can even be applied to non-boolean operands. From the [documentation](https://docs.python.org/3/reference/expressions.html?highlight=precedence#boolean-operations):" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "> In the context of Boolean operations, and also when expressions are used by control flow statements, the following values are interpreted as false: \n", "> `False`, `None`, numeric zero of all types, and empty strings and containers (including strings, tuples, lists, dictionaries, sets and frozensets). \n", "> All other values are interpreted as true." ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "**Exercise** How does the following code work?" ] }, { "cell_type": "code", "execution_count": 50, "metadata": { "ExecuteTime": { "end_time": "2020-09-12T01:21:36.876517Z", "start_time": "2020-09-12T01:21:33.652090Z" }, "slideshow": { "slide_type": "-" }, "tags": [ "remove-output" ] }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "abc\n", "You have entered abc\n" ] } ], "source": [ "print(\"You have entered\", input() or \"nothing\")" ] }, { "cell_type": "markdown", "metadata": { "nbgrader": { "grade": true, "grade_id": "or", "locked": false, "points": 0, "schema_version": 3, "solution": true, "task": false }, "slideshow": { "slide_type": "-" } }, "source": [ "- The code replaces empty user input by the default string `nothing` because an empty string is regarded as False in a boolean operation.\n", "- If user input is non-empty, it is regarded as True in the boolean expression and returned immediately as the value of the boolean operation." ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "**Is an empty string equal to False?**" ] }, { "cell_type": "code", "execution_count": 21, "metadata": { "ExecuteTime": { "end_time": "2020-09-15T00:07:47.564050Z", "start_time": "2020-09-15T00:07:47.557602Z" }, "slideshow": { "slide_type": "-" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Is empty string equal False? False\n" ] } ], "source": [ "print(\"Is empty string equal False?\", \"\" == False)" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "- An empty string is regarded as false in a boolean operation but\n", "- a *comparison operation is not a boolean operation*, even though it forms a boolean expression." ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "## Conditional Constructs" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "Consider writing a program that sorts values in *ascending* order. \n", "A *sorting algorithm* refers to the procedure of sorting values in order." ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "### If-Then Construct" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "**How to sort two values?**" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "Given two values are stored as `x` and `y`, we want to \n", "- `print(x,y)` if `x <= y`, and\n", "- `print(y,x)` if `y < x`." ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "Such a program flow is often represented by a flowchart like the following:" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "![sort_two_values(x,y) version 1](images/sort_two_values1.svg)" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "Python provides the [`if` statement](https://docs.python.org/3/reference/compound_stmts.html#the-if-statement) to implement the above [*control flow*](https://en.wikipedia.org/wiki/Control_flow) specified by the diamonds." ] }, { "cell_type": "code", "execution_count": 23, "metadata": { "ExecuteTime": { "end_time": "2020-09-12T01:37:02.500747Z", "start_time": "2020-09-12T01:37:02.460501Z" }, "code_folding": [ 8 ], "scrolled": true, "slideshow": { "slide_type": "-" } }, "outputs": [ { "data": { "application/vnd.jupyter.widget-view+json": { "model_id": "d6966cf1b6994a45a00441b7e7024ea8", "version_major": 2, "version_minor": 0 }, "text/plain": [ "interactive(children=(Text(value='1', description='x'), Text(value='0', description='y'), Output()), _dom_clas…" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "# Sort two values using if statement\n", "def sort_two_values(x, y):\n", " if x <= y:\n", " print(x, y)\n", " if y < x:\n", " print(y, x)\n", "\n", "\n", "@interact(x=\"1\", y=\"0\")\n", "def sort_two_values_app(x, y):\n", " sort_two_values(eval(x), eval(y))" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "We can visualize the execution as follows:" ] }, { "cell_type": "code", "execution_count": 24, "metadata": { "ExecuteTime": { "end_time": "2020-09-12T01:37:18.924680Z", "start_time": "2020-09-12T01:37:18.914274Z" }, "slideshow": { "slide_type": "-" } }, "outputs": [ { "data": { "text/html": [ "\n", " \n", " " ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "%%mytutor -h 350\n", "def sort_two_values(x, y):\n", " if x <= y:\n", " print(x, y)\n", " if y < x:\n", " print(y, x)\n", "\n", "\n", "sort_two_values(1, 0)\n", "sort_two_values(1, 2)" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "Python use indentation to indicate code blocks or *suite*: \n", "- `print(x, y)` (Line 5) is indented to the right of `if x <= y:` (Line 4) to indicate it is the body of the if statement.\n", "- For convenience, `if y < x: print(y, x)` (Line 6) is a one-liner for an `if` statement that only has one line in its block.\n", "- Both `if` statements (Line 4-6) are indented to the right of `def sort_two_values(x,y):` (Line 3) to indicate that they are part of the body of the function `sort_two_values`." ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "**How to indent?**" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "- The [style guide](https://www.python.org/dev/peps/pep-0008/#indentation) recommends using 4 spaces for each indentation. \n", "- In IPython, you can simply type the `tab` key and IPython will likely enter the correct number of spaces for you." ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "**What if you want to leave a block empty?**" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "In programming, it is often useful to delay detailed implementations until we have written an overall skeleton. \n", "To leave a block empty, Python uses the keyword [`pass`](https://docs.python.org/3/tutorial/controlflow.html#pass-statements)." ] }, { "cell_type": "code", "execution_count": 61, "metadata": { "ExecuteTime": { "end_time": "2020-09-12T01:45:57.392097Z", "start_time": "2020-09-12T01:45:57.386403Z" }, "slideshow": { "slide_type": "-" } }, "outputs": [], "source": [ "# write a code skeleton\n", "def sort_two_values(x, y):\n", " pass\n", " # print the smaller value first followed by the larger one\n", "\n", "\n", "sort_two_values(1, 0)\n", "sort_two_values(1, 2)" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "Without `pass`, the code will fail to run, preventing you from checking other parts of the code." ] }, { "cell_type": "code", "execution_count": 63, "metadata": { "ExecuteTime": { "end_time": "2020-09-12T01:51:11.655679Z", "start_time": "2020-09-12T01:51:11.649080Z" }, "code_folding": [], "slideshow": { "slide_type": "fragment" } }, "outputs": [], "source": [ "# You can add more details to the skeleton step-by-step\n", "def sort_two_values(x, y):\n", " if x <= y:\n", " pass\n", " # print x before y\n", " if y < x:\n", " pass # print y before x\n", "\n", "\n", "sort_two_values(1, 0)\n", "sort_two_values(1, 2)" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "### If-Then-Else Construct" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "The sorting algorithm is not efficient enough. Why not? \n", "Hint: `(x <= y) and not (y < x)` is a *tautology*, i.e., always true." ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "To improve the efficient, we should implement the following program flow." ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "-" } }, "source": [ "![sort_two_values(x,y) version 2](images/sort_two_values2.svg)" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "This can be done by the `else` clause of the [`if` statement](https://docs.python.org/3/tutorial/controlflow.html#if-statements)." ] }, { "cell_type": "code", "execution_count": 64, "metadata": { "ExecuteTime": { "end_time": "2020-09-12T01:56:37.522264Z", "start_time": "2020-09-12T01:56:37.509438Z" }, "slideshow": { "slide_type": "fragment" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "0 1\n", "1 2\n" ] }, { "data": { "text/html": [ "\n", " \n", " " ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "%%mytutor -h 350\n", "def sort_two_values(x, y):\n", " if x <= y:\n", " print(x, y)\n", " else:\n", " print(y, x)\n", "\n", "\n", "sort_two_values(1, 0)\n", "sort_two_values(1, 2)" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "We can also use a [*conditional expression*](https://docs.python.org/3/reference/expressions.html#conditional-expressions) to shorten the code." ] }, { "cell_type": "code", "execution_count": 65, "metadata": { "ExecuteTime": { "end_time": "2020-09-12T01:56:45.805718Z", "start_time": "2020-09-12T01:56:45.759289Z" }, "code_folding": [ 5 ], "slideshow": { "slide_type": "-" } }, "outputs": [ { "data": { "application/vnd.jupyter.widget-view+json": { "model_id": "f59bbbbfbd1b41f5bd614f465004cc4a", "version_major": 2, "version_minor": 0 }, "text/plain": [ "interactive(children=(Text(value='1', description='x'), Text(value='0', description='y'), Output()), _dom_clas…" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "def sort_two_values(x, y):\n", " print((\"{0} {1}\" if x <= y else \"{1} {0}\").format(x, y))\n", "\n", "\n", "@interact(x=\"1\", y=\"0\")\n", "def sort_two_values_app(x, y):\n", " sort_two_values(eval(x), eval(y))" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "**Exercise** Explain why the followings have syntax errors." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "ExecuteTime": { "end_time": "2020-09-08T11:03:52.336321Z", "start_time": "2020-09-08T11:03:52.330951Z" }, "slideshow": { "slide_type": "-" } }, "outputs": [], "source": [ "1 if True" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "ExecuteTime": { "end_time": "2020-09-08T11:03:46.129347Z", "start_time": "2020-09-08T11:03:46.121932Z" }, "slideshow": { "slide_type": "-" } }, "outputs": [], "source": [ "x = 1 if True else x = 0" ] }, { "cell_type": "markdown", "metadata": { "nbgrader": { "grade": true, "grade_id": "conditional-expression", "locked": false, "points": 0, "schema_version": 3, "solution": true, "task": false }, "slideshow": { "slide_type": "-" } }, "source": [ "A conditional expression must be an expression:\n", "1. It must give a value under all cases. To enforce that, `else` keyword must be provided.\n", "1. An assignment statement does not return any value and therefore cannot be used for the conditional expression. \n", " `x = 1 if True else 0` is valid because `x =` is not part of the conditional expression." ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "### Nested Conditionals" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "Consider sorting three values instead of two. A feasible algorithm is as follows:" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "![sort_three_values(x,y,z)](images/sort_three_values.svg) " ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "We can implement the flow using *nested conditional constructs*:" ] }, { "cell_type": "code", "execution_count": 25, "metadata": { "ExecuteTime": { "end_time": "2020-09-12T01:58:22.115132Z", "start_time": "2020-09-12T01:58:22.099108Z" }, "code_folding": [], "slideshow": { "slide_type": "-" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "0 1 2\n", "0 1 2\n", "0 1 2\n", "0 1 2\n", "0 1 2\n", "0 1 2\n" ] } ], "source": [ "def sort_three_values(x, y, z):\n", " if x <= y <= z:\n", " print(x, y, z)\n", " else:\n", " if x <= z <= y:\n", " print(x, z, y)\n", " else:\n", " if y <= x <= z:\n", " print(y, x, z)\n", " else:\n", " if y <= z <= x:\n", " print(y, z, x)\n", " else:\n", " if z <= x <= y:\n", " print(z, x, y)\n", " else:\n", " print(z, y, x)\n", "\n", "\n", "def test_sort_three_values():\n", " sort_three_values(0, 1, 2)\n", " sort_three_values(0, 2, 1)\n", " sort_three_values(1, 0, 2)\n", " sort_three_values(1, 2, 0)\n", " sort_three_values(2, 0, 1)\n", " sort_three_values(2, 1, 0)\n", "\n", "\n", "test_sort_three_values()" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "Imagine what would happen if we have to sort many values. \n", "To avoid an excessively long line due to the indentation, Python provides the `elif` keyword that combines `else` and `if`." ] }, { "cell_type": "code", "execution_count": 67, "metadata": { "ExecuteTime": { "end_time": "2020-09-12T01:59:42.132273Z", "start_time": "2020-09-12T01:59:42.119646Z" }, "slideshow": { "slide_type": "fragment" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "0 1 2\n", "0 1 2\n", "0 1 2\n", "0 1 2\n", "0 1 2\n", "0 1 2\n" ] } ], "source": [ "def sort_three_values(x, y, z):\n", " if x <= y <= z:\n", " print(x, y, z)\n", " elif x <= z <= y:\n", " print(x, z, y)\n", " elif y <= x <= z:\n", " print(y, x, z)\n", " elif y <= z <= x:\n", " print(y, z, x)\n", " elif z <= x <= y:\n", " print(z, x, y)\n", " else:\n", " print(z, y, x)\n", "\n", "\n", "test_sort_three_values()" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "**Exercise** The above sorting algorithm is inefficient because some conditions may be checked more than once. Improve the program to eliminate duplicate checks. \n", "\n", "*Hint:* Do not use chained comparison operators or compound boolean expressions." ] }, { "cell_type": "code", "execution_count": 88, "metadata": { "ExecuteTime": { "end_time": "2020-09-13T11:16:08.525091Z", "start_time": "2020-09-13T11:16:08.515562Z" }, "nbgrader": { "grade": false, "grade_id": "efficient-sort_three_values", "locked": false, "schema_version": 3, "solution": true, "task": false }, "slideshow": { "slide_type": "-" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "10 14 17\n" ] } ], "source": [ "def sort_three_values(x, y, z):\n", " if x <= y:\n", " if y <= z:\n", " print(x, y, z)\n", " elif x <= z:\n", " print(x, z, y)\n", " else:\n", " print(z, x, y)\n", " ### BEGIN SOLUTION\n", " elif z <= y:\n", " print(z, y, x)\n", " elif z <= x:\n", " print(y, z, x)\n", " else:\n", " print(y, x, z)\n", " ### END SOLUTION\n", "\n", "\n", "sort_three_values(10, 17, 14)" ] } ], "metadata": { "celltoolbar": "Slideshow", "kernelspec": { "display_name": "Python 3 (ipykernel)", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.8.8" }, "latex_envs": { "LaTeX_envs_menu_present": true, "autoclose": false, "autocomplete": true, "bibliofile": "biblio.bib", "cite_by": "apalike", "current_citInitial": 1, "eqLabelWithNumbers": true, "eqNumInitial": 1, "hotkeys": { "equation": "Ctrl-E", "itemize": "Ctrl-I" }, "labels_anchors": false, "latex_user_defs": false, "report_style_numbering": false, "user_envs_cfg": false }, "rise": { "enable_chalkboard": true, "scroll": true, "theme": "white" }, "toc": { "base_numbering": 1, "nav_menu": { "height": "195px", "width": "330px" }, "number_sections": true, "sideBar": true, "skip_h1_title": true, "title_cell": "Table of Contents", "title_sidebar": "Contents", "toc_cell": false, "toc_position": { "height": "454.418px", "left": "1533px", "top": "110.284px", "width": "435.325px" }, "toc_section_display": true, "toc_window_display": false }, "widgets": { "application/vnd.jupyter.widget-state+json": { "state": {}, "version_major": 2, "version_minor": 0 } } }, "nbformat": 4, "nbformat_minor": 4 }